package com.company.JUC.生产者消费者;

import java.util.concurrent.locks.Lock;

/**
 * @author ylr
 * @version 1.0.0
 * @ClassName PipeSolution.java
 * @Description TODO 所谓“管程法”，就是在生产者和消费者间建立一个共享缓冲区
 * @createTime 2021年12月11日 17:15:00
 */
public class PipeSolution {

    public static void main(String[] args) {
        // 创建一个缓冲区
        Container container = new Container(5);

        // 开启生产者线程
        for (int i = 0; i < 3; i++) {
            Thread thread = new Thread(new Producer(container));
            thread.setName("线程: "+i);
            thread.start();
        }

        // 开启消费者线程
        new Consumer(container).start();
    }

}


//产品
class Product {
    //产品名字
    public final String name;


    Product(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}

//缓冲区
class Container {
    private final Product[] productsBuffer; //产品数组
    private final int capacity;//容量
    private volatile int size;//当前数组大小

    //构造
    public Container(int capacity) {
        this.productsBuffer = new Product[capacity];
        this.capacity = capacity;
        this.size = 0;
    }

    public synchronized void put(Product product) throws InterruptedException {
        //判断缓存区是否满了,满了阻塞
        if (this.size >= this.capacity) {
            this.wait();
        }
        // 现在缓冲区内发现了空余位置
        // 向缓冲区内存入这件产品
        productsBuffer[size++] = product;
        System.out.println(Thread.currentThread().getName()+"  " + product.getName() + "  size: "+size);
        // 告知其它线程缓冲区内存入产品已完成
        this.notify();
    }

    // 从缓冲区中拿出一件产品
    // 修饰为同步方法，保证同一时刻只有一个线程可以从缓冲区中拿出产品
    public synchronized Product get() throws InterruptedException {
        // 若缓冲区内没有产品
        if (size <= 0) {
            // 暂缓取出产品，进行等待，直到缓冲区中出现产品
            this.wait();
        }
        // 现在缓冲区内有产品了
        // 从缓冲区内取出一件产品
        Product product = productsBuffer[--size];
        System.out.println("Consumer: Get " + product.getName());
        // 告知其它线程从缓冲区中取出产品已完成
        this.notify();
        // 将取出的产品返回
        return product;
    }


}


// 生产者
class Producer extends Thread {
    private final Container container;

    public Producer(Container container) {
        this.container = container;
    }

    @Override
    public void run() {
        // 生产者只负责生产
        try {
            produce();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void produce() throws InterruptedException {

        for (int i = 1; i <= 50; i++) {
            container.put(new Product("Product " + i));
        }
    }
}

// 消费者
class Consumer extends Thread {
    private final Container container;

    public Consumer(Container container) {
        this.container = container;
    }

    @Override
    public void run() {
        // 消费者只负责消费
        try {
            consume();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void consume() throws InterruptedException {
        for (int i = 1; i <= 50*3; i++) {
            Product product = container.get();
        }
    }
}
